#!/usr/bin/env python
# -*- coding: utf-8 -*-

from twisted.internet.protocol import Protocol, ClientFactory
from base64 import b64encode
from config import config
from os.path import basename

debug = 1

class RTSPClient(Protocol):
    def __init__(self):
        self.id = None
        self.conf = config()
        self.wait_description = False
    def setId(self, im_id):
        self.id = im_id
    def connectionMade(self):
        self.session = 1
        if self.conf.cameras[self.id]['login']:
            authstring = 'Authorization: Basic ' + b64encode(self.conf.cameras[self.id]['login']+':'+self.conf.cameras[self.id]['pass']) + '\r\n'
        else:
            authstring = ''
        to_send = """\
OPTIONS rtsp://""" + self.conf.cameras[self.id]['ip'] + self.conf.cameras[self.id]['request'] + """ RTSP/1.0\r
""" + authstring + """CSeq: 1\r
User-Agent: CamProxy\r
\r
"""
        self.transport.write(to_send)
        if debug:
            print "Camproxy says:\n", to_send
    
    def dataReceived(self, data):
        if debug:
            print "Server said:\n", data
        data_ln = data.strip().split("\r\n", 5)
        
        if data_ln[0] == "RTSP/1.0 200 OK" or self.wait_description:
            if 'audio_track' in self.conf.cameras[self.id]:
                cseq_audio = 1
            else:
                cseq_audio = 0
            to_send = ''
            if data_ln[1] == "CSeq: 1":
                to_send = """\
DESCRIBE rtsp://""" + self.conf.cameras[self.id]['ip'] + self.conf.cameras[self.id]['request'] + """ RTSP/1.0\r
CSeq: 2\r
Accept: application/sdp\r
User-Agent: CamProxy\r
\r
"""
            elif data_ln[1] == "CSeq: 2" or self.wait_description:
                data_sp = data.strip().split("\r\n\r\n", 1)
                if len(data_sp) == 2 or self.wait_description:
                    video = audio = False
                    is_MJPEG = False
                    video_track = ''
                    audio_track = ''
                    if len(data_sp) == 2:
                        s = data_sp[1]
                    elif self.wait_description:
                        s = data
                    for line in s.strip().split('\r\n'):
                        if line.startswith('m=video'):
                            video = True
                            audio = False
                        if line.startswith('m=audio'):
                            video = False
                            audio = True
                        if video:
                            params = line.split(':', 1)
                            if params[0] == 'a=rtpmap':
                                if params[1].startswith('26 JPEG'):
                                    is_MJPEG = True
                            elif params[0] == 'a=control':
                                video_track = params[1]
                        if audio:
                            params = line.split(':', 1)
                            if params[0] == 'a=control':
                                audio_track = params[1]
                    if not is_MJPEG:
                        print "Stream", self.conf.cameras[self.id]['ip'] + self.conf.cameras[self.id]['request'], "is not a MJPEG stream!"
                    if video_track: self.conf.cameras[self.id]['video_track'] = "rtsp://" + self.conf.cameras[self.id]['ip'] + self.conf.cameras[self.id]['request'] + "/" + basename(video_track)
                    if audio_track: self.conf.cameras[self.id]['audio_track'] = "rtsp://" + self.conf.cameras[self.id]['ip'] + self.conf.cameras[self.id]['request'] + "/" + basename(audio_track)
                    to_send = """\
SETUP """ + self.conf.cameras[self.id]['video_track'] + """ RTSP/1.0\r
CSeq: 3\r
Transport: RTP/AVP;unicast;client_port=4176"""+ str(self.id*2) + """-4176"""+ str(1+self.id*2) + """\r
User-Agent: CamProxy\r
\r
"""
                    self.wait_description = False
                else:
                    self.wait_description = True
            elif data_ln[1] == "CSeq: 3" and 'audio_track' in self.conf.cameras[self.id]:
                self.session = data_ln[5].strip().split(' ')[1]
                to_send = """\
SETUP """ + self.conf.cameras[self.id]['audio_track'] + """ RTSP/1.0\r
CSeq: 4\r
Transport: RTP/AVP;unicast;client_port=787"""+ str(8+self.id*2) + """-787"""+ str(9+self.id*2) + """\r
Session: """ + self.session + """\r
User-Agent: CamProxy\r
\r
"""
            elif data_ln[1] == "CSeq: "+str(3+cseq_audio):
                to_send = """\
PLAY rtsp://""" + self.conf.cameras[self.id]['ip'] + self.conf.cameras[self.id]['request'] + """/ RTSP/1.0\r
CSeq: """ + str(4+cseq_audio) + """\r
Session: """ + self.session + """\r
Range: npt=0.000-\r
User-Agent: CamProxy\r
\r
"""
            elif data_ln[1] == "CSeq: "+str(4+cseq_audio):
                if debug:
                    print "PLAY"
                pass
                
            elif data_ln[1] == "CSeq: "+str(5+cseq_audio):
                if debug:
                    print "TEARDOWN"
                pass

            if to_send:
                self.transport.write(to_send)
                if debug:
                    print "Camproxy says:\n", to_send

class RTSPFactory(ClientFactory):
    
    def __init__(self, im_id):
        self.protocol = RTSPClient
        self.id = im_id
    def buildProtocol(self, addr):
        prot = ClientFactory.buildProtocol(self, addr)
        prot.setId(self.id)
        return prot

    def clientConnectionLost(self, connector, reason):
        connector.connect()
    #    print "RTSP: Connection lost"
        #reactor.stop()


